Что такое function overloading (перегрузка функций) в TypeScript?
Что это такое
Function overloading (перегрузка функций) — это способ описать в TypeScript несколько вариантов сигнатур одной функции. Каждая сигнатура задаёт свой набор типов входных параметров и тип возвращаемого значения. Сама функция при этом остаётся одна — перегрузка существует только на уровне типов и проверяется компилятором, в JavaScript после компиляции никаких отдельных функций не будет.
Это нужно, когда поведение и возвращаемый тип функции зависят от типа переданных аргументов, а обычная сигнатура с union-типами не даёт TypeScript достаточно точной информации.
Как объявляются перегрузки
Синтаксис такой: сначала идёт список сигнатур-объявлений (без тела), а последней — реализующая сигнатура с телом функции. Реализация не видна снаружи — вызывающий код может использовать только те сигнатуры, что объявлены выше.
// сигнатуры перегрузки
function combine(a: string, b: string): string;
function combine(a: number, b: number): number;
// реализация — не видна снаружи, должна покрывать все перегрузки
function combine(a: string | number, b: string | number): string | number {
if (typeof a === 'string' && typeof b === 'string') {
return a + b;
}
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
throw new Error('Аргументы должны быть одного типа');
}
combine('a', 'b'); // string
combine(1, 2); // number
combine('a', 1); // ошибка компиляции — нет подходящей перегрузки
Зачем это нужно, если есть union-типы
Можно было бы написать одну сигнатуру function combine(a: string | number, b: string | number): string | number, но тогда TypeScript не свяжет тип результата с конкретной комбинацией аргументов — вызывающему коду пришлось бы вручную сужать тип результата. Перегрузка же даёт точный тип на каждый конкретный вызов, и автодополнение в IDE подсказывает именно те варианты, что реально поддерживаются.
Как TypeScript выбирает перегрузку
Компилятор проверяет сигнатуры сверху вниз и выбирает первую, под которую подходят переданные аргументы. Поэтому порядок объявления важен: более специфичные и часто используемые перегрузки обычно ставят раньше более общих.
Отличие от runtime-полиморфизма
Важно понимать, что overloading в TypeScript — это чисто типовая конструкция. В отличие от языков вроде Java или C++, где перегрузка существует и во время выполнения, в TypeScript в рантайме есть только одна функция — та, что описана в реализации. Вся логика ветвления по типам аргументов (typeof, instanceof и т.д.) пишется вручную внутри тела функции.
Что хочет услышать интервьюер
Понимание, что overloading существует только на уровне типов и стирается при компиляции в JS
Умение написать несколько сигнатур и одну реализующую функцию, объединяющую их через union-тип
Понимание, что реализация не видна снаружи — вызывающий код ограничен объявленными сигнатурами
Знание, что порядок сигнатур важен — TypeScript выбирает первую подходящую
Понимание разницы между overloading и обычным параметром с union-типом
Пример: Перегрузка функции создания DOM-элемента
function createElement(tag: 'a'): HTMLAnchorElement;
function createElement(tag: 'canvas'): HTMLCanvasElement;
function createElement(tag: string): HTMLElement;
function createElement(tag: string): HTMLElement {
// реализация одна для всех перегрузок
return document.createElement(tag);
}
const link = createElement('a'); // HTMLAnchorElement
const canvas = createElement('canvas'); // HTMLCanvasElement
const div = createElement('div'); // HTMLElement
Типичные ошибки
Путают перегрузку функций в TypeScript с рантайм-полиморфизмом как в Java или C++
Считают, что сигнатура реализации доступна снаружи функции, хотя она скрыта
Не покрывают в теле реализации все объявленные перегрузки, из-за чего получают ошибку компиляции
Располагают более общую сигнатуру выше специфичной, и TypeScript выбирает не ту перегрузку
Используют overloading там, где достаточно одного union-типа, излишне усложняя код


